package clara;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;

import pam.PAM;
import types.SubSet;
import clusterMaker.BaseData;
import functions.NCD;


public class CLARA
{   
// CLARA PAM algorithm implementation
	
    public static SubSet[] ApplyCLARA(SubSet mainset, int k, int numSamples, double sampleSize)
    {
    	int[] bestMedoids = new int[k];
    	int[] tempMedoidsSample = new int[k];
    	int[] tempMedoidIndexs = new int[k];
    	int numElements= mainset.getSize();
        double bestMedoidsDist = Double.MAX_VALUE;
        int sampSize = (int)(sampleSize*mainset.getSize()/100);
        int sampleCount = numSamples;
        String[] sample = new String[sampSize];
        Map<Integer, String> samplePoints = new Hashtable<Integer, String>();
        
        for(int i = 0; i < sampleCount; i++)
        {
            //Take a sample and use PAM on it to get medoids
        	
            samplePoints.clear();
            Random rand = new Random();
            int index;
            int counter = 0;
			while (samplePoints.size() < sampSize)
            {	
				counter++;
				index = rand.nextInt(numElements-1);
                if (!samplePoints.containsValue(mainset.getElement(index)))
                    samplePoints.put(index, mainset.getElement(index));
                if(counter > numElements * 10 )
                	samplePoints.put(index, mainset.getElement(index));
            }
			int j=0;
            for (String test : samplePoints.values()){
                sample[j]=test;
                j++;
            }

                      
    		BaseData sdata = new BaseData(sample);
    		
    		PAM pam = new PAM(sdata);
    		
    		// start PAM algorithm
    		pam.cluster(k);
    		
    		// get medoids from the PAM algorithm
    		tempMedoidsSample=pam.getMedoids();
   		
    		pam = null;
    		System.gc();
    		
    		//Map the sample medoids back to the full data set
    		@SuppressWarnings("rawtypes")
			Iterator it = samplePoints.entrySet().iterator();
    	    while (it.hasNext()) {
    	        @SuppressWarnings("rawtypes")
				Map.Entry pairs = (Map.Entry)it.next();
    	        if(pairs.getValue().equals(sample[tempMedoidsSample[0]]))
    	        	tempMedoidIndexs[0] = (int) pairs.getKey();
    	        if(pairs.getValue().equals(sample[tempMedoidsSample[1]]))
    	        	tempMedoidIndexs[1] = (int) pairs.getKey();
    	        it.remove(); 
    	    }
    	    
    	    System.gc(); 
            //Now apply the sample medoids to the full data set
            double sqrdDist = 0.0;
            double tempDist = 0.0;
            for(j=0; j<k; j++){
            	for(int ii=0; ii<mainset.getSize(); ii++){
            		tempDist= NCD.getNCD(mainset.getElement(ii), mainset.getElement(tempMedoidIndexs[j]));
            		sqrdDist= sqrdDist + tempDist;
            	}
            }
            
            
            if(sqrdDist < bestMedoidsDist)
            {
                bestMedoidsDist = sqrdDist;
                System.arraycopy(tempMedoidIndexs, 0, bestMedoids, 0, k);
            }
            
                     
        }  
        
        int i,j;
        double tempDist1 =0.0;
        double tempDist2 =0.0;
        SubSet[] set = new SubSet[k];
        for(j=0; j<k; j++)
        	set[j] = new SubSet();
        
        set[0].setBestMedoid(mainset.getElement(bestMedoids[0]));
        set[1].setBestMedoid(mainset.getElement(bestMedoids[1]));
        
        //final partition of Data set into k sub-sets
        for(i=0; i<mainset.getSize(); i++){
        	tempDist1= NCD.getNCD(mainset.getElement(i), mainset.getElement(bestMedoids[0]));
        	tempDist2= NCD.getNCD(mainset.getElement(i), mainset.getElement(bestMedoids[1]));
        	if(tempDist1<= tempDist2)
        		set[0].setElement(mainset.getElement(i));
        	else
        		set[1].setElement(mainset.getElement(i));

        }
        
       System.gc(); 
       return set; 

    }
    
}
